home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / infoserv / gopher / Unix / gopher-gateways / techinfo / techinpher / v1.0 / gopherchild.c.Z / gopherchild.c
Encoding:
C/C++ Source or Header  |  1993-02-23  |  8.7 KB  |  347 lines

  1. /*
  2.   This software is copyrighted by the University of Pennsylvania.
  3.   Read COPYRIGHT for details.
  4.   */
  5.  
  6. #include <stdio.h>
  7. #include <sys/types.h>
  8. #include <sys/wait.h>
  9. #include <time.h>
  10. #include <sys/resource.h>
  11. #include <signal.h>
  12. #include <sys/stat.h>
  13. #include <fcntl.h>
  14. #include <limits.h>
  15. #include <string.h>
  16.  
  17. #include "network.h"
  18. #include "pdb.h"
  19. #include "node.h"
  20. #include "gophernodes.h"
  21.   
  22. extern int      addednewnodes;
  23. extern int      tables_changed;
  24. extern short    todaysdate;
  25. extern pid_t    savedatastruct_pid;
  26. extern struct   s1 *getnode_bygopherinfo(char **fields);
  27. extern struct   s1 *init_gopher_node (char **fields, long nid, short lastu,
  28.                       int chkexists);
  29. extern void     nio_send_file(int s, char *fn, long stpt, long req, int isnlist);
  30. extern void     send_empty_document (int s);
  31. extern void     send_empty_menu (int s);
  32. extern char     *nodeinfostr(long nid, struct s1 *node, int flgfmt);
  33.  
  34.  
  35. extern CONN     conntab[];
  36. #define    conn_established(cn)    (conntab[cn].c_socket != -1)
  37.  
  38. extern void remove_helper(WAITFORHELPER *ptr)
  39. {
  40.   int i, found;
  41.  
  42.   if (ptr == NULL)
  43.     return;
  44.  
  45.   kill (ptr->pid, SIGTERM); /* just in case child is out there */
  46.   do_free (ptr->file);
  47.   do_free (ptr->cachefile);
  48.   /* DONT free the ptr->node, it's part of the datastruct */
  49.  
  50.   for (i=0, found = 0; !found && i < FD_SETSIZE; ) {
  51.     if (conntab[i].c_hptr == ptr)
  52.       found  = 1;
  53.     else
  54.       i++;
  55.   }
  56.   free (ptr);
  57.   if (found) 
  58.     conntab[i].c_hptr = NULL;
  59.   return;
  60. }
  61.  
  62. int next_id;
  63.  
  64. /* increments next id in memory + on disk */
  65. /* assumes that get_nextid() has been called already */
  66. static void
  67. inc_nextid(void)
  68. {
  69.   char            line[20];
  70.   int dfd;
  71.  
  72.   if ((dfd = open(NEXTID_FILE, O_WRONLY | O_TRUNC | O_CREAT)) <= 0)
  73.     {
  74.       printf("error incrementing next id\n");
  75.       return;
  76.     }
  77.   next_id++;
  78.   sprintf(line, "%d\n", next_id);
  79.   write(dfd, line, strlen(line));
  80.   close(dfd);
  81.   return;
  82. }
  83.  
  84. /* reads the next id from disk */
  85. extern void
  86.   get_nextid(void)
  87. {
  88.   char            line[20];
  89.   int             red;
  90.   int             dfd;
  91.   
  92.   if ((dfd = open(NEXTID_FILE, O_RDONLY)) <= 0){
  93.     printf("error getting next id\n");
  94.     return;
  95.   }
  96.   red = read(dfd, line, 20);
  97.   if (red <= 0){
  98.     printf("error reading next id\n");
  99.     return;
  100.   }
  101.   line[red] = '\0';
  102.   next_id = atoi(line);
  103.   close(dfd);
  104.   return;
  105. }
  106.  
  107. static void conv_textfile(FILE *ifile, char *filnam)
  108. {
  109.   FILE        *ofile;
  110.   char        line[NLINE_MAXLEN];
  111.   char        *cp;
  112.  
  113.   ofile = fopen(filnam, "w");
  114.   if (ofile == NULL) {
  115.     fprintf (stderr, "Unable to open temp nlist file\n");
  116.     perror(filnam);
  117.     return;
  118.   }
  119.   while (fgets (line,NLINE_MAXLEN-1,ifile) != NULL) {
  120.     cp = rindex (line, '\r');
  121.     if (cp) 
  122.       if (*(cp+1) == '\n') {
  123.     *cp = '\n';
  124.     *(cp+1) = 0;
  125.       }
  126.     /* gopher protocol: text file ends with a . on a line by itself */
  127.     if (strcmp(line, ".\n") == 0)
  128.       break;
  129.     else
  130.       fprintf (ofile, "%s", line);
  131.   }
  132.   fclose (ofile);
  133. }
  134.  
  135.  
  136. static void child_punt (char gophertype, long nodeid, int sock, int flgsfmt)
  137. {
  138.   char *cp;
  139.  
  140.   if (gophertype == GOPHTYP_TEXT || gophertype == GOPHTYP_GIF ||
  141.       gophertype == GOPHTYP_IMAGE) {
  142.     send_empty_document(sock);
  143.   }
  144.   else if (gophertype == GOPHTYP_MENU) {
  145.     /* send this-
  146.        2:
  147.        0:nodeinfo of node we were working on
  148.        1:nodeinfo of reserved node that says "menu not available"
  149.        */
  150.     cp = (char *) malloc (2*BUFSIZ);
  151.     sprintf (cp, "2:\n0:%s\n", nodeinfostr(nodeid, NULL, flgsfmt));
  152.     strcat (cp, "1:");
  153.     strcat (cp, nodeinfostr(MENU_NOT_AVAILABLE, NULL, flgsfmt));
  154.     strcat (cp, "\n.\r\n");
  155.     sendbuf(cp, strlen(cp), sock);
  156.     /* sendbuf will free cp */
  157.   }
  158.   else {
  159.     send_empty_menu (sock);
  160.   }
  161. }
  162.  
  163. static int create_cached_nlist (FILE *ifile, char *tempname)
  164. {
  165.   FILE *tempfile;
  166.   char line[BUFSIZ];
  167.   char *gophfields[NUMFIELDS_GOPHER];
  168.   int numf;
  169.   struct s1 *node;
  170.   int numlines;
  171.  
  172.   tempfile = fopen (tempname, "w");
  173.   if (tempfile == NULL) {
  174.     fprintf (stderr, "Unable to write temp output nlist file\n");
  175.     perror (tempname);
  176.     return 0;
  177.   }
  178.  
  179.   /* ifile is an already open FILE */
  180.   for (rewind (ifile), numlines = 0;
  181.        fgets(line, sizeof(line)-1, ifile) != NULL; ) {
  182.     if (*line != GOPHTYP_DUPSRV) {
  183.       parsefields (line, gophfields, &numf, GOPHER_DLM, NUMFIELDS_GOPHER);
  184.       if (numf >= NUMFIELDS_GOPHER) {
  185.     node = getnode_bygopherinfo(gophfields);
  186.     if (node == NULL) {  /* create a new node in tables */
  187.       get_nextid();
  188.       node = init_gopher_node (gophfields, next_id, todaysdate, 0);
  189.       inc_nextid();
  190.       addednewnodes++;
  191.       tables_changed++;
  192.     }
  193.  
  194.     /*    gopher info is already known, therefore just use the existing nodeid */
  195.  
  196.     fprintf (tempfile, "%ld\n", node->nodeid);
  197.     numlines++;
  198.       }   /* enough gopher fields */
  199.     }     /* it wasn't a dupl server line */
  200.   }    /* foreach line of ifile */
  201.   fclose (tempfile);
  202.   return 1;
  203. }
  204.  
  205.  
  206.  
  207.  
  208.  
  209. static int find_helper_conn (pid_t pid)
  210. {
  211.   int found;
  212.   int con;
  213.   
  214.   for (found = 0, con = 0; con < FD_SETSIZE && !found;) {
  215.     if (conn_established(con) && (conntab[con].c_hptr) &&
  216.     (conntab[con].c_hptr)->pid == pid) {
  217.       found = 1;
  218.     }
  219.     else
  220.       con++;
  221.   }
  222.   if (!found)
  223.     return -1;
  224.   else
  225.     return con;
  226. }
  227.  
  228.  
  229. extern void catch_child (void)
  230. {
  231.   pid_t pid;
  232.   union wait status;
  233.   struct rusage rusage;
  234.   int c, found;
  235.   FILE *childfile;
  236.   WAITFORHELPER *hptr;
  237.   char *filename2;
  238.   sigset_t currmask;
  239.   
  240.   pid = wait3 (&status, WNOHANG, &rusage);
  241.   
  242.   if (pid == 0) {
  243.     fprintf (stderr, "Funny, wait3 returned pid 0!\n");
  244.     return;  /* don't know if there's a connect out there waiting */
  245.   }
  246.   else if (pid < 0) {
  247.     fprintf (stderr, "wait3 returned %d\n", pid);
  248.     perror ("wait3");
  249.     return;   /* don't know if there's a connect out there waiting */
  250.   }
  251.   
  252.   /* (pid > 0) */
  253.  
  254.   fprintf (stderr, "\nT=%d.  Caught pid %d, exitstat = %d.  ",
  255.        time(0), pid, WEXITSTATUS(status));
  256.  
  257.   if ((c=find_helper_conn (pid)) < 0) {
  258.     if (pid != savedatastruct_pid)
  259.       fprintf (stderr, "Unknown what connection %d went with\n", pid);
  260.     else {
  261.       savedatastruct_pid = 0;
  262.       fprintf(stderr, "save_datastruct child.\n");
  263.     }
  264.     return;
  265.   }
  266.   else
  267.     fprintf (stderr, "Goes with conn #%d, sock %d\n",  c, conntab[c].c_socket);
  268.  
  269.  
  270.   hptr = conntab[c].c_hptr;
  271.   /* Assumption: c_hptr->node still points to a valid node in a1[] */
  272.  
  273.   /* if child exited with non-zero status, must be an error */
  274.   if (WEXITSTATUS(status) != 0) {
  275.     child_punt((hptr->node)->gophertype, (hptr->node)->nodeid,
  276.            conntab[c].c_socket, conntab[c].c_output_fmt);
  277.     unlink (hptr->file);
  278.     return;
  279.   }
  280.  
  281.   childfile = fopen (hptr->file,"r");
  282.   if (childfile == NULL) {  /* File wasn't there ??? */
  283.     fprintf (stderr, "Could not open child's output file\n");
  284.     perror (hptr->file);
  285.     child_punt ((hptr->node)->gophertype, (hptr->node)->nodeid,
  286.         conntab[c].c_socket, conntab[c].c_output_fmt);
  287.     return;
  288.   }
  289.   else {
  290.     filename2 = tempnam(CACHEDIR, "convert");
  291.     /* has to be the same dir as the cache because rename() needs that */
  292.     
  293.     switch ((hptr->node)->gophertype) {
  294.     case GOPHTYP_IMAGE:
  295.     case GOPHTYP_GIF: 
  296.       /* No conversion is needed for GIF files */
  297.       fclose (childfile);
  298.       rename (hptr->file, hptr->cachefile);
  299.       nio_send_file(conntab[c].c_socket, hptr->cachefile,
  300.             hptr->startpoint, hptr->requested, 0);
  301.       remove_helper(hptr);
  302.       do_free(filename2);
  303.       break;
  304.       
  305.     case GOPHTYP_TEXT:
  306.       conv_textfile (childfile, filename2); 
  307.       rename (filename2, hptr->cachefile);
  308.       nio_send_file(conntab[c].c_socket, hptr->cachefile,
  309.             hptr->startpoint, hptr->requested, 0);
  310.       fclose (childfile); /* conv_... did NOT close file */
  311.       unlink (hptr->file); /* remove child's file */
  312.       remove_helper(hptr);
  313.       do_free (filename2);
  314.       break;
  315.       
  316.     case GOPHTYP_MENU:
  317.     case GOPHTYP_SEARCH:
  318.       if (!create_cached_nlist (childfile, filename2)) {
  319.     child_punt((hptr->node)->gophertype,
  320.            (hptr->node)->nodeid,
  321.            conntab[c].c_socket, conntab[c].c_output_fmt);
  322.       }
  323.       else {
  324.     rename (filename2, hptr->cachefile);
  325.     send_cached_nlist (hptr->node, conntab[c].c_socket, hptr->cachefile,
  326.                conntab[c].c_output_fmt);
  327.       }
  328.       fclose (childfile);
  329.       unlink (hptr->file);  /* remove child's file from the filesystem */
  330.       remove_helper(hptr);  /* remove the buf associated with child */
  331.       do_free(filename2);
  332.       break;
  333.  
  334.     default:
  335.       fprintf (stderr, "catch_child() doesn't handle type '%c'.",
  336.            (hptr->node)->gophertype);
  337.       child_punt ((hptr->node)->gophertype, (hptr->node)->nodeid,
  338.           conntab[c].c_socket, conntab[c].c_output_fmt);
  339.       fclose (childfile); /* close file */
  340.       unlink (hptr->file); /* remove child's file */
  341.       remove_helper(hptr);
  342.       do_free (filename2);
  343.       break;
  344.     }
  345.   } /* childfile was okay */
  346. }
  347.